#pragma once

#include  "Parser.hpp"
#include "Socket.hpp"
#include "InetAddr.hpp"
#include "Logger.hpp"
#include "Protocol.hpp"

#include <memory>
#include <unistd.h>
#include <signal.h>
#include <functional>

using callback_t = std::function<std::string(std::string &)>;

class TcpServer
{
private:
    void HandlerRequest(std::shared_ptr<Socket> sockfd, InetAddr addr)
    {
        std::string inbuffer; // 接受缓冲区
        // 长服务，只要连接在一直接受数据、处理数据、返回
        while (true)
        {
            // 从sockfd 中读取数据
            ssize_t n = sockfd->Recv(&inbuffer); // 将获取到的数据放在inbuffer 中
            if (n < 0)
            {
                // 读取失败，直接退出
                break;
            }
            else if (n == 0)
            {
                // 网络中recv 的返回值为0，代表着对端连接关闭
                LOG(LogLevel::DEBUG) << "客户端连接关闭:" << addr.ToString() << ",  me too ";
                break;
            }
            else
            {
                // 读取数据成功
                // 此处可以回调出去，交给上层处理读取到的数据
                // debug 将获取到的数据打印出来
                std::cout << "client says# " << inbuffer << std::endl;

                // 反序列化、处理数据、序列化  --> 封装成一个模块
                // inbuffer 中是请求 --> 解包、反序列化
                std::string sendstr = _cb(inbuffer);
                if(sendstr.empty()) continue;
                // 返回应答
                LOG(LogLevel::DEBUG) << "服务器处理请求成功，返回：" << sendstr;
                sockfd->Send(sendstr);
            }
        }
        // 关闭文件描述符
        sockfd->Close();
    }

public:
    TcpServer(uint16_t port , callback_t cb)
        : _port(port), _listensockfd(std::make_shared<TcpSocket>()),_cb(cb)
    {
        // 调用Socket 中创建套接字的方法
        _listensockfd->BuildListenSocket(_port);
    }

    // 服务器启动
    void Run()
    {
        // signal(SIGCHLD, SIG_IGN); //将对于信号的忽略提到了守护进程函数中
        while (true)
        {
            InetAddr addr;
            // 获取客户端连接
            std::shared_ptr<Socket> sockfd = _listensockfd->Accept(&addr);
            if (sockfd == nullptr)
            {
                continue;
            }

            LOG(LogLevel::INFO) << "获取连接成功, " << addr.ToString();

            // 从sockfd 中读取数据，创建子进程回调出去处理
            // 父子进程各自关闭自己不适用的文件描述符，避免文件描述符泄漏
            if (fork() == 0)
            {
                LOG(LogLevel::DEBUG) << "创建子进程成功";
                _listensockfd->Close();
                HandlerRequest(sockfd, addr);
                exit(0); // 处理完io，子进程就退出
            }
            // 避免父进程等待子进程 --> 信号捕捉、忽略
            sockfd->Close();
        }
    }

private:
    // 端口号记忆套接字描述符
    uint16_t _port;
    std::shared_ptr<Socket> _listensockfd;
    callback_t _cb;
};